﻿using System.Collections.Generic;
using MetaVideoEditorEvolved.AddIn.Entity;
using MetaVideoEditorEvolved.Helper;

/*
 * Created by SharpDevelop.
 * User: fred
 * Date: 11/09/2011
 * Time: 08:30
 * 
 * To change this template use Tools | Options | Coding | Edit Standard Headers.
 */
namespace MetaVideoEditorEvolved.Engine
{
	using System;
	using System.AddIn.Hosting;
	using System.Collections.ObjectModel;
	using System.Linq;
	
	using MetaVideoEditorEvolved.AddIn.HostViews;
	using MetaVideoEditorEvolved.Engine.Entity;


	/// <summary>
	/// Description of AddInProviderManager.
	/// </summary>
	public class AddInProviderManager : AddInManager
	{
		private static AddInProviderManager currentInstance;
		private static object syncRoot = new Object();
		private List<KeyValuePair<AddInInformation, ProviderView>> providerAddins = new List<KeyValuePair<AddInInformation, ProviderView>>();
		
		public AddInProviderManager()
		{
			Collection<AddInToken> providerAddIns = AddInStore.FindAddIns(typeof(AddIn.HostViews.ProviderView), addInPath);

			InsertAddIns(providerAddIns, AddInType.Provider);
			
			InitializeAddIn();
		}
		
		public static AddInProviderManager Current
		{
			get
			{
				if(currentInstance == null)
				{
					lock (syncRoot)
					{
						currentInstance = new AddInProviderManager();
					}
				}
				
				return currentInstance;
			}
		}
		
		public void InitializeAddIn()
		{
			providerAddins.Clear();
			
			var addinOrder = from ai in AddIns
				orderby ai.Index
				select ai;
			
			foreach (var addin in addinOrder) {
				if(addin.IsEnable)
				{
					if(!(providerAddins.Where((o) => o.Key == addin).Any()))
					{
						ProviderView addInInstance = addin.Token.Activate<ProviderView>(AddInSecurityLevel.FullTrust);
						providerAddins.Add(new KeyValuePair<AddInInformation, ProviderView>(addin, addInInstance));
					}
				}
			}
			
			AddIns = (from ai in AddIns
			          orderby ai.Index
			          select ai).ToList();
		}
		
		public override void SaveAllConfiguration()
		{
			base.SaveAllConfiguration();
			
			providerAddins = new List<KeyValuePair<AddInInformation, ProviderView>>();
			
			InitializeAddIn();
		}
		
		public Collection<ProviderSearchMedia> FindPossible(Entity.MediaType mediaType, string searchName)
		{
			Tracer.TracerInstance.TraceInformation("Start FindPossible in the AddIn Provider Manager for " + searchName);
			Collection<ProviderSearchMedia> results = new Collection<ProviderSearchMedia>();
			
			foreach (var addInInstance in providerAddins) {
				var resultsAddin = addInInstance.Value.FindPossible(new ProviderSearchRequest
				                                                    {
				                                                    	Name = searchName,
				                                                    	Type = (AddIn.Entity.MediaType)Enum.Parse(typeof(AddIn.Entity.MediaType), mediaType.ToString())
				                                                    });
				
				foreach (var addin in resultsAddin) {
					results.Add(new ProviderSearchMedia
					            {
					            	Id = addin.Id,
					            	MediaUrl =addin.MediaUrl,
					            	Name = addin.Name,
					            	OriginalName = addin.OriginalName,
					            	Overview = addin.Overview,
					            	Picture = addin.Picture,
					            	Year = addin.Year,
					            	ProviderId = addInInstance.Key.AssemblyId,
					            	ProviderName = addInInstance.Key.Name,
					            	Rating = addin.Rating
					            });
				}
			}
			
			Tracer.TracerInstance.TraceInformation("End FindPossible in the AddIn Provider Manager for " + searchName + " - Count:" + results.Count);
			
			return results;
		}
		
		public Serie FetchSerie(string id, Guid providerId)
		{
			foreach (var element in providerAddins) {
				if(element.Key.AssemblyId == providerId)
				{
					ProviderView addInInstance = element.Value;
					
					var resultAddin = addInInstance.FetchSerie(id);
					
					Serie serie = new Serie();
					
					if(resultAddin != null)
					{
						serie.Backdrops = resultAddin.Backdrops != null ? new Collection<Uri>(resultAddin.Backdrops) : new Collection<Uri>();
						serie.CastMembers = resultAddin.CastMembers != null ? new Collection<CastMember>((from cm in resultAddin.CastMembers
						                                                select new CastMember
						                                                {
						                                                	Activity = cm.Activity,
						                                                	FullName = cm.FullName,
						                                                	Picture = cm.Picture,
						                                                	Role = cm.Role
						                                                }).ToList()) : new Collection<CastMember>();
						serie.Duration = resultAddin.Duration;
						serie.Genres = resultAddin.Genres != null ? new Collection<string>(resultAddin.Genres) : new Collection<string>();
						serie.Graphicals = resultAddin.Graphicals != null ? new Collection<Uri>(resultAddin.Graphicals) : new Collection<Uri>();
						serie.Id = resultAddin.Id;
						serie.Name = resultAddin.Name;
						serie.Overview = resultAddin.Overview;
						serie.Posters = resultAddin.Posters != null ? new Collection<Uri>(resultAddin.Posters) : new Collection<Uri>();
						serie.Rating = resultAddin.Rating;
						serie.Studios = resultAddin.Studios != null ? new Collection<string>(resultAddin.Studios) : new Collection<string>();
						serie.Year = resultAddin.Year;
					}
					
					return serie;
				}
			}
			
			return null;
		}
		
		public Season FetchSeason(string serieId, int seasonNumber, Guid providerId)
		{
			Season season = null;
			
			foreach (var element in providerAddins) {
				if(element.Key.AssemblyId == providerId ||
				   providerId == Guid.Empty)
				{
					ProviderView addInInstance = element.Value;
					
					var resultAddin = addInInstance.FetchSeason(serieId, seasonNumber);
					
					if(resultAddin != null)
					{
						season = new Season();
						season.Number = resultAddin.Number;
						season.Images = resultAddin.Images != null ? new Collection<Uri>(resultAddin.Images) : new Collection<Uri>();
					}
				}
			}
			
			return season;
		}
		
		public Episode FetchEpisode(string serieId, int seasonNumber, int episodeNumber, Guid providerId)
		{
			Episode episode = null;
			
			foreach (var element in providerAddins) {
				if(element.Key.AssemblyId == providerId ||
				   providerId == Guid.Empty)
				{
					ProviderView addInInstance = element.Value;
					
					var resultAddin = addInInstance.FetchEpisode(serieId, seasonNumber, episodeNumber);
					
					if(resultAddin != null)
					{
						episode = new Episode();
						episode.Number = resultAddin.Number;
						episode.Id = resultAddin.Id;
						episode.Images = resultAddin.Images != null ? new Collection<Uri>(resultAddin.Images) : new Collection<Uri>();
						episode.Name = resultAddin.Name;
						episode.Overview = resultAddin.Overview;
						episode.Rating = resultAddin.Rating;
						episode.Year = resultAddin.Year;
						episode.Writers = resultAddin.Writers != null ? new Collection<string>(resultAddin.Writers): new Collection<string>();
						episode.Directors = resultAddin.Directors != null ? new Collection<string>(resultAddin.Directors) : new Collection<string>();
						episode.GuestStars = resultAddin.GuestStars != null ? new Collection<string>(resultAddin.GuestStars) : new Collection<string>();
						episode.SeasonNumber = seasonNumber;
						episode.FirstAired = resultAddin.FirstAired;
					}
				}
			}
			
			return episode;
		}
		
		public Movie FetchMovie(int id, Guid providerId)
		{
			try
			{
				Tracer.TracerInstance.TraceInformation("Start FetchMovie in the AddIn Provider Manager for the id" + id);
				
				foreach (var element in providerAddins) {
					if(element.Key.AssemblyId == providerId)
					{
						ProviderView addInInstance = element.Value;
						
						var resultAddin = addInInstance.FetchMovie(id);
						
						if(resultAddin != null)
						{
							Movie movie = new Movie();
							movie.Backdrops = resultAddin.Backdrops != null ? new Collection<Uri>(resultAddin.Backdrops) : new Collection<Uri>();
							movie.CastMembers = resultAddin.CastMembers != null ? new Collection<CastMember>((from cm in resultAddin.CastMembers
							                                                select new CastMember
							                                                {
							                                                	Activity = cm.Activity,
							                                                	FullName = cm.FullName,
							                                                	Picture = cm.Picture,
							                                                	Role = cm.Role
							                                                }).ToList()) : new Collection<CastMember>();
							movie.Duration = resultAddin.Duration;
							movie.Genres = resultAddin.Genres != null ? new Collection<string>(resultAddin.Genres) : new Collection<string>();
							movie.Id = resultAddin.Id;
							movie.Nationalities = resultAddin.Countries != null ? new Collection<string>(resultAddin.Countries) : new Collection<string>();
							movie.Year = resultAddin.Year;
							movie.OriginalTitle = resultAddin.OriginalTitle;
							movie.Overview = resultAddin.Overview;
							movie.Posters = resultAddin.Posters != null ? new Collection<Uri>(resultAddin.Posters) : new Collection<Uri>();
							movie.Rating = resultAddin.Rating;
							movie.Studios = resultAddin.Studios != null ? new Collection<string>(resultAddin.Studios) : new Collection<string>();
							movie.Title = resultAddin.Title;
							movie.Trailers = resultAddin.Trailers != null ? new Collection<Trailer>((from t in resultAddin.Trailers
							                                          select new Trailer
							                                          {
							                                          	HighQuality = t.HighQuality,
							                                          	MediumQuality =t.MediumQuality,
							                                          	LowQuality = t.LowQuality,
							                                          	DefaultPath = t.DefaultPath,
							                                          	Language = (Language)Enum.Parse(typeof(Language),t.Language.ToString())
							                                          }).ToList()) : new Collection<Trailer>();
							
							Tracer.TracerInstance.TraceInformation("End FetchMovie in the AddIn Provider Manager for the id" + id + "- Data is found");
							
							return movie;
						}
					}
				}
				
				Tracer.TracerInstance.TraceInformation("End FetchMovie in the AddIn Provider Manager for the id" + id + "- Data is not found");
				
				return null;
			}
			catch(Exception ex)
			{
				Tracer.TracerInstance.TraceError("Exception in the AddIn Provider Manager for the id " + id + " " + ex.ToString());
				
				return null;
			}
		}
		
		public Collection<ProviderSearchMedia> AutoFind(Entity.MediaType mediaType,string searchName)
		{
			searchName = searchName.ToLower();
			
			var findPossible = FindPossible(mediaType, searchName).Where((o) => o.Name.ToLower() == searchName || (!string.IsNullOrEmpty(o.OriginalName) && o.OriginalName.ToLower() == searchName));
			
			foreach (var element in AddInProviderManager.Current.AddIns) {
				if((from fp in findPossible
				    where fp.ProviderId == element.AssemblyId
				    select fp).Count() > 1)
				{
					return new Collection<ProviderSearchMedia>();
				}
			}
			
			return new Collection<ProviderSearchMedia>(findPossible.ToList());
		}
		
		public void ShowOption(AddInInformation addInInformation)
		{
			AddInProcess addInProcess = new AddInProcess();
			addInProcess.Start();

			ProviderView addInInstance =  addInInformation.Token.Activate<ProviderView>(addInProcess, AddInSecurityLevel.FullTrust);
			
			addInInstance.ShowOption();
			
			addInProcess.Shutdown();
		}
		
		
		public bool HasOption(AddInInformation addInInformation)
		{
			ProviderView addInInstance = null;
			
			var addin = providerAddins.Where((o) => o.Key == addInInformation);
			
			if(addin.Any())
			{
				addInInstance = addin.First().Value;
			}
			else
			{
				addInInstance = addInInformation.Token.Activate<ProviderView>(AddInSecurityLevel.FullTrust);
			}
			
			return addInInstance.HasOption();
		}
	}
}
